package com.weaver.smartext.core.parser;


import com.weaver.smartext.core.anno.Parse;
import com.weaver.smartext.core.domain.StructablePdfDto;
import com.weaver.smartext.core.domain.TextAnalysis;
import com.weaver.smartext.core.enums.FileEnums;
import com.weaver.smartext.core.util.StreamUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.io.RandomAccessBufferedFileInputStream;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineNode;
import org.apache.pdfbox.text.PDFTextStripper;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description:
 * @title: PdfParser
 * @Author Star_Chen
 * @Date: 2023/3/31 20:33
 * @Version 1.0
 */
@Parse(fileType = {FileEnums.PDF})
public class PdfParser implements Parser<StructablePdfDto> {

    //此处用于改类的流复用，但是多的话会有OOM问题
    private byte[] bytes;

    @Override
    public StructablePdfDto parser(String path) {

        StructablePdfDto pdfDto = new StructablePdfDto();

        pdfDto.setContent(getContent(path));
        pdfDto.setHeads(getTitleAndPages(path));
        return pdfDto;
    }


    @Override
    public StructablePdfDto parser(File file) {
        return null;
    }

    /**
     * @return com.weaver.smarttext.core.domain.StructablePdfDto
     * @Author Star_Chen
     * @Description 用pdfbox解析内容，读取本地路径
     * @Date 21:33 2023/4/4
     * @Param [file]
     **/
    public StructablePdfDto parser() {
        StructablePdfDto pdfDto = new StructablePdfDto();
        File file = new File("C:\\Users\\Administrator\\Downloads\\如何开发一个EB组件.pdf");
        PDDocument pdDocument = null;
        try {
            PDFTextStripper pdfTextStripper = new PDFTextStripper();
            pdDocument = PDDocument.load(file);
            pdfDto.setContent(pdfTextStripper.getText(pdDocument));
            pdfDto.setRows(cleanContext(pdfDto));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                pdDocument.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return pdfDto;
    }

    /**
     * @return com.weaver.smarttext.core.domain.StructablePdfDto
     * @Author Star_Chen
     * @Description tika 解析流
     * @Date 21:33 2023/4/4
     * @Param [textAnalysis]
     **/
    @Override
    public StructablePdfDto parser(TextAnalysis textAnalysis) {
        StructablePdfDto pdfDto = new StructablePdfDto();
        bytes = StreamUtils.inputToByteArray(textAnalysis.getInputStream());

        pdfDto.setContent(parseInputStream(new ByteArrayInputStream(bytes)));
        pdfDto.setHeads(getTitleAndPages());
        pdfDto.setRows(cleanContext(pdfDto));
        return pdfDto;
    }

    /**
     * @return java.lang.String[]
     * @Author Star_Chen
     * @Description 清洗不规则数据形成行
     * @Date 18:14 2023/4/4
     * @Param [structablePdfDto]
     **/
    public String[] cleanContext(StructablePdfDto structablePdfDto) {
        //回车换行分割
        String[] str = structablePdfDto.getContent().split("[\n\r,]");
        List<String> collect = Arrays.stream(str).filter(StringUtils::isNotBlank).collect(Collectors.toList());

        String context = String.join(",", collect);
        structablePdfDto.setContent(context);
        return str;
    }

    /**
     * @return java.lang.String
     * @Author Star_Chen
     * @Description 获取pdf正文的逻辑
     * @Date 21:01 2023/4/3
     * @Param [path]
     **/
    public String getContent(String path) {

        File file = new File(path);

        PDDocument pdDocument;
        PDFParser pdfParser;
        String text = "";

        try (RandomAccessBufferedFileInputStream is = new RandomAccessBufferedFileInputStream(file)) {
            pdfParser = new PDFParser(is);

            pdfParser.parse();
            pdDocument = pdfParser.getPDDocument();
            PDFTextStripper textStripper = new PDFTextStripper();
            text = textStripper.getText(pdDocument);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return text;

    }

    /**
     * @return java.util.List<com.weaver.smarttext.core.domain.StructablePdfDto.Head>
     * @Author Star_Chen
     * @Description 获取pdf标题和页数
     * @Date 10:46 2023/4/4
     * @Param [path]
     **/
    public List<StructablePdfDto.Head> getTitleAndPages(String path) {

        File file = new File(path);

        PDDocument pdDocument = null;
        PDFParser pdfParser;
        List<StructablePdfDto.Head> list = new ArrayList<>();

        try (RandomAccessBufferedFileInputStream randomAccessBufferedFileInputStream = new RandomAccessBufferedFileInputStream(file)) {
            pdfParser = new PDFParser(randomAccessBufferedFileInputStream);
            pdfParser.parse();

            pdDocument = pdfParser.getPDDocument();
            PDDocumentOutline documentOutline = pdDocument.getDocumentCatalog().getDocumentOutline();
            if (documentOutline != null) {
                printBookmarks(documentOutline, "", list);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                pdDocument.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return list;
    }


    private List<StructablePdfDto.Head> getTitleAndPages() {

        List<StructablePdfDto.Head> list = new ArrayList<>();
        PDDocument pdDocument = null;

        try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
             RandomAccessBufferedFileInputStream randomAccessBufferedFileInputStream = new RandomAccessBufferedFileInputStream(byteArrayInputStream)) {

            PDFParser parser = new PDFParser(randomAccessBufferedFileInputStream);

            parser.parse();
            pdDocument = parser.getPDDocument();

            PDDocumentOutline documentOutline = pdDocument.getDocumentCatalog().getDocumentOutline();
            if (documentOutline != null) {
                printBookmarks(documentOutline, "", list);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                pdDocument.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return list;
    }

    /**
     * @return void
     * @Author Star_Chen
     * @Description 打印pdf书签
     * @Date 10:45 2023/4/4
     * @Param [bookmark, indentation, heads]
     **/
    private void printBookmarks(PDOutlineNode bookmark, String indentation, List<StructablePdfDto.Head> heads) throws IOException {
        PDOutlineItem current = bookmark.getFirstChild();
        while (current != null) {
            int pages = 0;
            if (current.getDestination() instanceof PDPageDestination) {
                PDPageDestination pd = (PDPageDestination) current.getDestination();
                pages = pd.retrievePageNumber() + 1;
            }
            if (current.getAction() instanceof PDActionGoTo) {
                PDActionGoTo gta = (PDActionGoTo) current.getAction();
                if (gta.getDestination() instanceof PDPageDestination) {
                    PDPageDestination pd = (PDPageDestination) gta.getDestination();
                    pages = pd.retrievePageNumber() + 1;
                }
            }
            StructablePdfDto.Head head = new StructablePdfDto.Head();
            head.setPage(pages == 0 ? null : String.valueOf(pages));
            head.setTitle(current.getTitle());
            heads.add(head);
            printBookmarks(current, indentation + "    ", heads);
            current = current.getNextSibling();
        }
    }
}
